﻿using Core.Utility.Extendsions.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace FastServer
{
    /// <summary>
    /// 应用服务集合扩展类
    /// </summary>
    public static class AppServiceCollectionExtension
    {
        /// <summary>
        /// Mvc 注入基础配置（带Swagger）
        /// </summary>
        /// <param name="mvcBuilder">Mvc构建器</param>
        /// <param name="configure"></param>
        /// <returns>IMvcBuilder</returns>
        public static IMvcBuilder AddInject(this IMvcBuilder mvcBuilder, Action<AddInjectOptions>? configure = null)
        {
            //使用 System.Text.Json 就不要使用 Newtonsoft.Json,二选一
            mvcBuilder
                .AddJsonOptions(options =>
                {
                    //采用 Newtonsoft.Json 方式接口返回值能够正常输出，
                    //但是 Swagger 界面中的 Example Values 依然显示小写字母开头的属性，
                    //这时只需要再添加 System.Text.Json 配置即可，如：
                    options.JsonSerializerOptions.PropertyNamingPolicy = null;
                    options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
                    //options.JsonSerializerOptions.Converters.AddDateFormatString("yyyy-MM-dd HH:mm:ss");
                    //options.JsonSerializerOptions.Converters.Add(new DateTimeOffsetJsonConverter());
                    //options.JsonSerializerOptions.Converters.Add(new DateTimeJsonConverter());
                    //在 .NET 5 中，System.Text.Json 并不支持处理循环引用问题，以下语句的解决方案只限用于 .NET 6 Preview 2+。
                    options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
                })
                .AddNewtonsoftJson(options =>
                {
                    var dateConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter
                    {
                        DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
                    };
                    options.SerializerSettings.Converters.Add(dateConverter);
                    //long转string
                    options.SerializerSettings.Converters.Add(new JsonLongParseStringConverter());
                    options.SerializerSettings.ContractResolver = new DefaultContractResolver();
                    options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
                    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                });

            mvcBuilder.Services.AddInject(configure);            
            return mvcBuilder;
        }

        /// <summary>
        /// 服务注入基础配置（带Swagger）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configure"></param>
        /// <returns>IMvcBuilder</returns>
        public static IServiceCollection AddInject(this IServiceCollection services, Action<AddInjectOptions>? configure = null)
        {
            // 载入服务配置选项
            var configureOptions = new AddInjectOptions();
            configure?.Invoke(configureOptions);

            //services.AddSwaggerDocument(AddInjectOptions.SwaggerGenConfigure)
            //        .AddDynamicApiControllers()
            //        .AddDataValidation(AddInjectOptions.DataValidationConfigure)
            //        .AddFriendlyException(AddInjectOptions.FriendlyExceptionConfigure);
            services.AddSwaggerDocument(AddInjectOptions.SwaggerGenConfigure);

            //swagger 使用Newtonsfot.json进行序列化
            //https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1498
            services.AddSwaggerGenNewtonsoftSupport();
            return services;
        }

        /// <summary>
        /// MiniAPI 服务注入基础配置（带Swagger）
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configure"></param>
        /// <returns>IMvcBuilder</returns>
        /// <remarks>https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0</remarks>
        public static IServiceCollection AddInjectMini(this IServiceCollection services, Action<AddInjectOptions>? configure = null)
        {
            // 载入服务配置选项
            var configureOptions = new AddInjectOptions();
            configure?.Invoke(configureOptions);

            //services.AddSwaggerDocument(AddInjectOptions.SwaggerGenConfigure)
            //        .AddDataValidation(AddInjectOptions.DataValidationConfigure)
            //        .AddFriendlyException(AddInjectOptions.FriendlyExceptionConfigure);
            services.AddSwaggerDocument(AddInjectOptions.SwaggerGenConfigure);

            return services;
        }

        /// <summary>
        /// Mvc 注入基础配置
        /// </summary>
        /// <param name="mvcBuilder">Mvc构建器</param>
        /// <param name="configure"></param>
        /// <returns>IMvcBuilder</returns>
        public static IMvcBuilder AddInjectBase(this IMvcBuilder mvcBuilder, Action<AddInjectOptions> configure = null)
        {
            mvcBuilder.Services.AddInjectBase(configure);

            return mvcBuilder;
        }

        /// <summary>
        /// Mvc 注入基础配置
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configure"></param>
        /// <returns>IMvcBuilder</returns>
        public static IServiceCollection AddInjectBase(this IServiceCollection services, Action<AddInjectOptions>? configure = null)
        {
            // 载入服务配置选项
            var configureOptions = new AddInjectOptions();
            configure?.Invoke(configureOptions);

            //services.AddDataValidation(AddInjectOptions.DataValidationConfigure)
            //        .AddFriendlyException(AddInjectOptions.FriendlyExceptionConfigure);

            return services;
        }

        /// <summary>
        /// Mvc 注入基础配置和规范化结果
        /// </summary>
        /// <param name="mvcBuilder"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IMvcBuilder AddInjectWithUnifyResult(this IMvcBuilder mvcBuilder, Action<AddInjectOptions>? configure = null)
        {
            mvcBuilder.Services.AddInjectWithUnifyResult(configure);

            return mvcBuilder;
        }

        /// <summary>
        /// 注入基础配置和规范化结果
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configure"></param>
        /// <returns></returns>
        public static IServiceCollection AddInjectWithUnifyResult(this IServiceCollection services, Action<AddInjectOptions>? configure = null)
        {
            services.AddInject(configure);
                    //.AddUnifyResult();

            return services;
        }

        ///// <summary>
        ///// Mvc 注入基础配置和规范化结果
        ///// </summary>
        ///// <typeparam name="TUnifyResultProvider"></typeparam>
        ///// <param name="mvcBuilder"></param>
        ///// <param name="configure"></param>
        ///// <returns></returns>
        //public static IMvcBuilder AddInjectWithUnifyResult<TUnifyResultProvider>(this IMvcBuilder mvcBuilder, Action<AddInjectOptions>? configure = null)
        //    where TUnifyResultProvider : class, IUnifyResultProvider
        //{
        //    mvcBuilder.Services.AddInjectWithUnifyResult<TUnifyResultProvider>(configure);

        //    return mvcBuilder;
        //}

        ///// <summary>
        ///// Mvc 注入基础配置和规范化结果
        ///// </summary>
        ///// <typeparam name="TUnifyResultProvider"></typeparam>
        ///// <param name="configure"></param>
        ///// <param name="services"></param>
        ///// <returns></returns>
        //public static IServiceCollection AddInjectWithUnifyResult<TUnifyResultProvider>(this IServiceCollection services, Action<AddInjectOptions>? configure = null)
        //    where TUnifyResultProvider : class, IUnifyResultProvider
        //{
        //    services.AddInject(configure)
        //            .AddUnifyResult<TUnifyResultProvider>();

        //    return services;
        //}

        /// <summary>
        /// 自动添加主机服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddAppHostedService(this IServiceCollection services)
        {
            // 获取所有 BackgroundService 类型，排除泛型主机
            var backgroundServiceTypes = App.EffectiveTypes.Where(u => typeof(IHostedService).IsAssignableFrom(u) && u.Name != "GenericWebHostService");
            var addHostServiceMethod = typeof(ServiceCollectionHostedServiceExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                .Where(u => u.Name.Equals("AddHostedService") && u.IsGenericMethod && u.GetParameters().Length == 1)
                                .FirstOrDefault();

            foreach (var type in backgroundServiceTypes)
            {
                addHostServiceMethod?.MakeGenericMethod(type).Invoke(null, new object[] { services });
            }

            return services;
        }

        /// <summary>
        /// 添加应用配置
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configure">服务配置</param>
        /// <returns>服务集合</returns>
        internal static IServiceCollection AddApp(this IServiceCollection services, Action<IServiceCollection> configure = null)
        {
            // 注册全局配置选项
            services.AddConfigurableOptions<AppSettingsOptions>();

            // 注册内存和分布式内存
            services.AddMemoryCache();
            services.AddDistributedMemoryCache();

            // 注册全局依赖注入
            //services.AddDependencyInjection();

            // 注册全局 Startup 扫描
            services.AddStartups();

            // 添加对象映射
            //services.AddObjectMapper();

            // 默认内置 GBK，Windows-1252, Shift-JIS, GB2312 编码支持
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            // 自定义服务
            configure?.Invoke(services);

            return services;
        }

        /// <summary>
        /// 添加 Startup 自动扫描
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <returns>服务集合</returns>
        internal static IServiceCollection AddStartups(this IServiceCollection services)
        {
            // 扫描所有继承 AppStartup 的类
            var startups = App.EffectiveTypes
                .Where(u => typeof(AppStartup).IsAssignableFrom(u) && u.IsClass && !u.IsAbstract && !u.IsGenericType)
                .OrderByDescending(u => GetStartupOrder(u));

            // 注册自定义 startup
            foreach (var type in startups)
            {
                var startup = Activator.CreateInstance(type) as AppStartup;
                App.AppStartups.Add(startup);

                // 获取所有符合依赖注入格式的方法，如返回值void，且第一个参数是 IServiceCollection 类型
                var serviceMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
                    .Where(u => u.ReturnType == typeof(void)
                        && u.GetParameters().Length > 0
                        && u.GetParameters().First().ParameterType == typeof(IServiceCollection));

                if (!serviceMethods.Any()) continue;

                // 自动安装属性调用
                foreach (var method in serviceMethods)
                {
                    method.Invoke(startup, new[] { services });
                }
            }

            return services;
        }

        /// <summary>
        /// 获取 Startup 排序
        /// </summary>
        /// <param name="type">排序类型</param>
        /// <returns>int</returns>
        private static int GetStartupOrder(Type type)
        {
            return !type.IsDefined(typeof(AppStartupAttribute), true) ? 0 : type.GetCustomAttribute<AppStartupAttribute>(true).Order;
        }
    }
}
